import pygame, time, random
import pygame_menu as menu
import numpy as np

from Map import Map, SCREEN_HEIGHT, SCREEN_WIDTH, MYSPEED, INIT_X, INIT_Y, RECOVERBUFFER, parser
from Character import Player, EnemyTank, Box
from Bullet import Bullet
from Wall import Wall
from Item import Item
from Music import Music, BgmMusic
from Server import upload_grade


class MainGame():

    def __init__(self, gameIdx):
        self.gameIdx = gameIdx
        self.key_list = []
        self.score = 0

        def get_position():
            x, y = np.nonzero(Map.diyMap)
            enemy_position = []
            for i in range(len(x)):
                if Map.diyMap[x[i]][y[i]] == 21:
                    enemy_position.append((x[i], y[i]))
            print(enemy_position)
            return enemy_position

        self.enemy_position = get_position()

    def startGame(self):
        """game subsystem control"""
        # load game setting
        parser(self.gameIdx)
        # 初始化窗口
        pygame.display.init()

        # 设置窗口的大小及显示
        Map.window = pygame.display.set_mode([SCREEN_WIDTH, SCREEN_HEIGHT])
        # 初始化我方坦克
        self.createMyTank()
        # 初始化敌方坦克

        # 初始化墙壁
        self.createWall()
        # 初始化道具
        self.createItem()
        # 设置窗口标题
        pygame.display.set_caption('DIY坦克大战')

        background = pygame.transform.scale(pygame.image.load(Map.background), (SCREEN_WIDTH, SCREEN_HEIGHT))
        # print(type(background))
        returnState = 0  # 0/game win 1/game over 2/game exit
        # 计数器，到达一定次数后刷新道具
        item_counter = 0
        totRecoverTime = Map.recoverTimes
        Map.Time = 0
        while True:
            Map.Time += 1
            self.createEnemyTank()
            Map.window.blit(background, (0, 0))
            # 减慢坦克移动速度
            time.sleep(0.02)
            # 给窗口设置填充色
            # Map.window.fill(BG_COLOR)
            # 获取事件
            flag = self.get_event()

            if flag:
                returnState = flag  # game exit
                break
            # 绘制文字

            if Map.myTank and Map.myTank.live:
                # 调用坦克显示方法
                Map.myTank.display()
            else:
                # 删除我方坦克
                del Map.myTank
                Map.myTank = None
            # 调用敌方坦克展示
            self.blitEnemyTank()
            # 调用我方子弹显示
            self.blitMyBullet()
            # 调用敌方子弹显示
            self.blitEnemyBullet()
            # 调用爆炸效果
            self.blitExplode()
            # 展示墙壁
            self.blitWall()
            # 展示道具
            if item_counter > 1000:
                self.createItem()
                item_counter = 0
            item_counter += 1
            self.blitItem()
            Map.window.blit(self.get_text_surface(
                'Kill %d Game Target %d Live %d/%d' % (self.score, Map.target, Map.recoverTimes, totRecoverTime),
                (255, 0, 0), 30), (10, 10))
            # Map.window.blit(self.get_text_surface('Try Your Best to live more time!',(0,255,0),30), (10, 50))
            Map.window.blit(self.get_text_surface(
                'Time %d s Score %d' % (Map.Time // 50, -(Map.Time // 50) + self.score * 20 + Map.recoverTimes * 20),
                (0, 255, 0), 30), (10, 50))

            if Map.myTank and Map.myTank.live:
                # 调用坦克移动方法
                if not Map.myTank.stop:
                    Map.myTank.takeAction()
                    # 检测是否与墙进行碰撞
                    Map.myTank.hitWall()
                    # 检测是否使用道具
                    Map.myTank.useItem()
                    # 检测我方坦克是否与敌方坦克发生碰撞
                    Map.myTank.hitEnemyTank()
            # 检测我方坦克是否存活
            if Map.myTank is None or not Map.myTank.live:
                if Map.recoverTimes == 1:
                    returnState = 1  # gameover
                    break
                else:
                    if Map.recoverBuffer > 0:
                        Map.recoverBuffer -= 1
                    else:
                        self.createMyTank()
                        Map.recoverTimes -= 1
                        Map.recoverBuffer = RECOVERBUFFER
            # 检测敌方坦克数量
            if self.score >= Map.target:
                returnState = 0
                break
            pygame.display.update()
        if Map.server:
            if returnState == 0:
                upload_grade(Map.uid, -(Map.Time // 50) + self.score * 20 + Map.recoverTimes * 20)
                Map.grade = -(Map.Time // 50) + self.score * 20 + Map.recoverTimes * 20
            if returnState == 1:
                upload_grade(Map.uid, -(Map.Time // 50) + self.score * 20 + Map.recoverTimes * 20)
                Map.grade = -(Map.Time // 50) + self.score * 20 + Map.recoverTimes * 20

        if returnState == 0:
            Map.grade = -(Map.Time // 50) + self.score * 20 + Map.recoverTimes * 20
        if returnState == 1:
            Map.grade = -(Map.Time // 50) + self.score * 20 + Map.recoverTimes * 20
        if returnState == 2:
            Map.grade = None
        self.modeExit()
        return returnState

    def blitWall(self):
        for wall in Map.wallList:
            if wall.live:
                # 调用墙壁的显示方法
                wall.display()
            else:
                # 从墙壁列表中移除
                Map.wallList.remove(wall)

    def blitItem(self):
        for item in Map.itemList:
            if item.live:
                item.display()
            else:
                Map.itemList.remove(item)

    def createWall(self):
        x, y = np.nonzero(Map.diyMap)
        for i in range(len(x)):
            # 初始化墙壁
            if Map.diyMap[x[i]][y[i]] < 5:
                if Map.diyMap[x[i]][y[i]] == 1:
                    hp = 1
                    path = 'img/walls.gif'
                if Map.diyMap[x[i]][y[i]] == 2:
                    hp = 22e5
                    path = 'img/steels.gif'
                wall = Wall(x[i] * 60, y[i] * 60, hp, path)
                # 将墙壁添加到列表中
                Map.wallList.append(wall)

    def createItem(self):
        x, y = np.nonzero(Map.diyMap)
        for i in range(len(x)):
            # 初始化墙壁
            if Map.diyMap[x[i]][y[i]] > 10:
                if Map.diyMap[x[i]][y[i]] == 11:
                    path = "img/star.gif"
                    item = Item(x[i] * 60, y[i] * 60, path)
                    Map.itemList.append(item)

    def getDIYwall(self):
        # 初始化窗口
        pygame.display.init()
        # 设置窗口的大小及显示
        Map.window = pygame.display.set_mode([SCREEN_WIDTH, SCREEN_HEIGHT])
        # 初始化我方选框
        self.createMyBox()
        # 设置窗口标题
        pygame.display.set_caption('DIY坦克大战-地图构建模式')

        # init map
        Map.diyMap = np.zeros((15, 10), np.int)

        while True:
            background = pygame.transform.scale(pygame.image.load("img/bg1.jpg"), (SCREEN_WIDTH, SCREEN_HEIGHT))
            Map.window.blit(background, (0, 0))
            Map.window.blit(self.get_text_surface('按C切换方块，按space放置方块,按esc完成DIY'), (10, 10))
            time.sleep(0.01)
            if Map.myTank and Map.myTank.live:
                # pass
                # 调用坦克显示方法
                Map.myTank.display()
            else:
                # 删除我方坦克
                del Map.myTank
                Map.myTank = None
            # 获取事件
            if self.get_event2():
                break

            # 展示墙壁
            self.blitWall()
            # 展示道具
            self.blitItem()

            if Map.myTank and Map.myTank.live:
                # 调用坦克移动方法
                if not Map.myTank.stop:
                    Map.myTank.move()

            pygame.display.update()
        np.save("map/level_0.npy", Map.diyMap.T)  # save diy map
        self.modeExit()

    def createMyTank(self):
        if Map.diy:
            flag = False
            while not flag:
                left = random.randint(0, SCREEN_WIDTH - 1) // 60
                top = random.randint(0, SCREEN_HEIGHT - 1) // 60

                # tmp = Player(left * 60, top * 60, MYSPEED,"./img/generated_DIY_tank.png")
                Attribute = Map.player_attributes
                speed = Attribute[0]
                Bullet_speed = Attribute[1]
                Bullet_capacity = Attribute[2]

                tmp = Player(left * 60, top * 60, speed, "./img/generated_DIY_tank.png", Bullet_speed, Bullet_capacity)

                flagHit = False
                for enemy in Map.enemyTankList:
                    if tmp.hit(enemy):
                        del tmp
                        flagHit = True
                        break
                if flagHit:
                    continue
                if Map.diyMap[left, top] == 0:
                    flag = True
                    Map.myTank = tmp
                else:
                    del tmp
        else:
            flag = False
            while not flag:
                left = random.randint(0, SCREEN_WIDTH - 1) // 60
                top = random.randint(0, SCREEN_HEIGHT - 1) // 60
                tmp = Player(left * 60, top * 60, MYSPEED)
                flagHit = False
                for enemy in Map.enemyTankList:
                    if tmp.hit(enemy):
                        del tmp
                        flagHit = True
                        break
                if flagHit:
                    continue
                if Map.diyMap[left, top] == 0:
                    flag = True
                    Map.myTank = tmp
                else:
                    del tmp
        # 创建Music对象
        if Map.bgm is None:
            Map.bgm = BgmMusic('img/start.mp3')
            Map.bgm.setVolume()
            # 播放音乐
            Map.bgm.play()

    def createMyBox(self):
        Map.myTank = Box(INIT_X, INIT_Y, MYSPEED)
        if Map.bgm is None:
            Map.bgm = BgmMusic('img/start.mp3')
            Map.bgm.setVolume()
            # 播放音乐
            Map.bgm.play()

    def blitExplode(self):
        for explode in Map.explodeList:
            if explode.live:
                explode.play()
            else:
                Map.explodeList.remove(explode)

    def blitMyBullet(self):
        # 循环遍历我方子弹存储列表
        for myBullet in Map.myBulletList:
            # 判断当前子弹是否碰到墙壁，如果碰到则从子弹列表中删除
            if myBullet.live:
                myBullet.display()
                myBullet.move()
                self.score += myBullet.hitEnemyTank()

                # 检测子弹是否射中墙壁
                myBullet.hitWall()
            else:
                Map.myBulletList.remove(myBullet)

    def blitEnemyBullet(self):
        for enemyBullet in Map.enemyBulletList:
            if enemyBullet.live:
                enemyBullet.display()
                enemyBullet.move()
                # 判断敌方坦克子弹是否与我方坦克碰撞
                enemyBullet.hitMyTank()
                # 检测敌方子弹是否与墙壁碰撞
                enemyBullet.hitWall()
            else:
                Map.enemyBulletList.remove(enemyBullet)

    def blitEnemyTank(self):
        # 循环遍历敌方坦克列表，展示敌方坦克
        for enemyTank in Map.enemyTankList:
            if enemyTank.live:
                # 未发生我方子弹击中，坦克显示
                enemyTank.display()
                enemyTank.takeAction()
                # 调用检测是否与墙壁进行碰撞
                enemyTank.hitWall()
                if Map.myTank and Map.myTank.live:
                    # 检测敌方坦克与我方坦克发生碰撞
                    enemyTank.hitMyTank()
                # 发射子弹
                enemyBullet = enemyTank.shot()
                if enemyBullet:
                    # 存储到子弹列表中
                    Map.enemyBulletList.append(enemyBullet)
            else:
                Map.enemyTankList.remove(enemyTank)

    def createEnemyTank(self):
        # 初始化敌方坦克，并将敌方坦克添加到列表中
        # 循坏生成敌方坦克
        enemy_attributes = Map.enemy_attributes

        for i in range(Map.enemyTankCount - len(Map.enemyTankList)):
            flag = False
            while not flag:
                if self.gameIdx == 0 and len(self.enemy_position)>0:
                    position = random.choice(self.enemy_position)
                    print(position)
                    left = position[0]
                    top = position[1]
                else:
                    left = random.randint(0, SCREEN_WIDTH - 1) // 60
                    top = random.randint(0, SCREEN_HEIGHT - 1) // 60
                speed = random.randint(1, 4)
                if Map.diy:
                    tmp = EnemyTank(left * 60, top * 60, enemy_attributes[0], img_path='img/generated_enemy_tank.png', \
                                    bullet_speed=enemy_attributes[1], shot_freq=enemy_attributes[2])
                else:
                    tmp = EnemyTank(left * 60, top * 60, speed)

                if Map.myTank and (Map.myTank.hit(tmp)):
                    del tmp
                    continue
                if self.gameIdx == 0:
                    flag = True
                    Map.enemyTankList.append(tmp)
                else:
                    if Map.diyMap[left, top] == 0:
                        flag = True
                        Map.enemyTankList.append(tmp)
                    else:
                        del tmp

    def modeExit(self):
        Map.bgm.stop()
        del Map.bgm
        Map.wallList.clear()  # 清空墙壁
        Map.enemyTankList.clear()
        Map.enemyBulletList.clear()
        Map.myBulletList.clear()
        Map.bgm = None

    def get_text_surface(self, text, color=(0, 255, 0), font_size=18):
        # 初始化字体模块
        pygame.font.init()
        # 获取字体对象
        font = pygame.font.SysFont('kaiti', font_size)
        # 绘制文本信息
        text_surface = font.render(text, True, color)
        return text_surface

    def key_down(self, key):
        if key == pygame.K_UP or \
                key == pygame.K_DOWN or \
                key == pygame.K_LEFT or \
                key == pygame.K_RIGHT:
            self.key_list.append(key)

    def key_up(self, key):
        if len(self.key_list) != 0:
            if key == pygame.K_UP or \
                    key == pygame.K_DOWN or \
                    key == pygame.K_LEFT or \
                    key == pygame.K_RIGHT:
                self.key_list.remove(key)

    def get_event(self):
        # 获取所有事件
        event_list = pygame.event.get()

        # 遍历所有事件
        for event in event_list:
            # 是否按下退出键
            if event.type == pygame.QUIT:
                exit(0)
            elif event.type == pygame.KEYDOWN:
                self.key_down(event.key)
                print(len(self.key_list))
                if len(self.key_list) == 2:
                    event.key = self.key_list[1]

                if event.key == pygame.K_ESCAPE:  # exit current mode
                    return 2
                # 当我方坦克被敌方子弹击中
                if not Map.myTank:
                    pass
                    # 判断按下的是q键，让坦克重生
                    # if event.key == pygame.K_q:
                    #     # 让我方坦克重生
                    #     self.createMyTank()
                if Map.myTank and Map.myTank.live:
                    # 键盘按下，判断上下左右
                    if event.key == pygame.K_LEFT:
                        Map.myTank.direction = 'L'
                        Map.myTank.stop = False
                        print('坦克向左移动')
                    elif event.key == pygame.K_DOWN:
                        Map.myTank.direction = 'D'
                        Map.myTank.stop = False
                        print('坦克向下移动')
                    elif event.key == pygame.K_RIGHT:
                        Map.myTank.direction = 'R'
                        Map.myTank.stop = False
                        print('坦克向右移动')
                    elif event.key == pygame.K_UP:
                        Map.myTank.direction = 'U'
                        Map.myTank.stop = False
                        print('坦克向上移动')
                    elif event.key == pygame.K_SPACE:
                        # 创建我方坦克子弹，同时限制子弹的数量为3
                        if len(Map.myBulletList) < Map.myTank.max_bullet_num:
                            myBullet = Map.myTank.shot()  # Bullet(Map.myTank.rect, Map.myTank.direction)
                            Map.myBulletList.append(myBullet)
                            # 我方坦克发射子弹的音效
                            music = Music('img/hit.wav')
                            music.setVolume()
                            music.play()
                            print('发射子弹')

            elif event.type == pygame.KEYUP:
                # 键盘松开，坦克停止移动
                self.key_up(event.key)
                if event.key == pygame.K_UP or \
                        event.key == pygame.K_DOWN or \
                        event.key == pygame.K_LEFT or \
                        event.key == pygame.K_RIGHT:
                    if Map.myTank and Map.myTank.live and len(self.key_list) == 0:
                        Map.myTank.stop = True
        return 0

    def get_event2(self):
        # 获取所有事件
        event_list = pygame.event.get()
        # 遍历所有事件
        for event in event_list:
            # 是否按下退出键
            if event.type == pygame.QUIT:
                exit(0)
            elif event.type == pygame.KEYDOWN:
                # 当我方坦克被敌方子弹击中
                # if not Map.myTank:
                #     # 判断按下的是Esc键，让坦克重生
                #     if event.key == pygame.K_ESCAPE:
                #         # 让我方坦克重生
                #         self.createMyTank()
                if event.key == pygame.K_ESCAPE:
                    return 1
                if Map.myTank and Map.myTank.live:
                    # 键盘按下，判断上下左右
                    if event.key == pygame.K_LEFT:
                        Map.myTank.direction = 'L'
                        Map.myTank.stop = False
                        print('坦克向左移动')
                    elif event.key == pygame.K_DOWN:
                        Map.myTank.direction = 'D'
                        Map.myTank.stop = False
                        print('坦克向下移动')
                    elif event.key == pygame.K_RIGHT:
                        Map.myTank.direction = 'R'
                        Map.myTank.stop = False
                        print('坦克向右移动')
                    elif event.key == pygame.K_UP:
                        Map.myTank.direction = 'U'
                        Map.myTank.stop = False
                        print('坦克向上移动')
                    elif event.key == pygame.K_c:
                        Map.myTank.changeType()
                    elif event.key == pygame.K_p:
                        Map.diyMap = np.zeros((15, 10), np.int)
                        Map.wallList = []
                        Map.itemList = []
                    elif event.key == pygame.K_SPACE:
                        # 创建我方坦克子弹，同时限制子弹的数量为3
                        if len(Map.myBulletList) < 30:
                            # myBullet = Bullet(MainGame.myTank)
                            # MainGame.myBulletList.append(myBullet)
                            # 我方坦克发射子弹的音效
                            Map.myTank.takeAction()
                            music = Music('img/hit.wav')
                            music.setVolume()
                            music.play()
                            print('放置墙体')

            elif event.type == pygame.KEYUP:
                # 键盘松开，坦克停止移动
                if event.key == pygame.K_UP or \
                        event.key == pygame.K_DOWN or \
                        event.key == pygame.K_LEFT or \
                        event.key == pygame.K_RIGHT:
                    if Map.myTank and Map.myTank.live:
                        Map.myTank.stop = True
        return 0
